﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using SMBL.Core;
using SMBL.Interface.Operation;
using SMBL.Interface.AbstractServer;

namespace SMBL.Control
{
    /// <summary>
    /// Control Center
    /// Used to process all exceptions occurred in the process
    /// @Author: Push
    /// </summary>
    public class ControlCenter
    {
        /////////////////////////////////////////////////////////////////////////
        // Parameter
        /////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Global Operation and Provider List
        /// @Author: Push
        /// </summary>
        private static Hashtable gOpProviderList;

        /// <summary>
        /// Global Abstract System and Operation list.
        /// </summary>
        private static Hashtable gOpASList;

        /// <summary>
        /// Global Abstract System instance and type list.
        /// </summary>
        private static Hashtable gTypeASList;

        /////////////////////////////////////////////////////////////////////////
        // Global API
        /////////////////////////////////////////////////////////////////////////

        public static Boolean AbstractServerRegister(
            SMBL.Interface.AbstractServer.IAS SingletonInstanceOftheAS)
        {
            // Already in the list.
            if (gTypeASList.ContainsKey(SingletonInstanceOftheAS.GetType())) return false;

            // Start the AS first.
            if (!SingletonInstanceOftheAS.Start()) return false;
            gTypeASList.Add(SingletonInstanceOftheAS.GetType().FullName, SingletonInstanceOftheAS);

            return true;
        }

        /// <summary>
        /// Initialize the Control Center.
        /// </summary>
        /// <returns>Statue</returns>
        public static Boolean Initialize()
        {
            // Initialize the gASTypeList.
            if (gTypeASList == null) gTypeASList = new Hashtable();
            // Initialize the global operation provider list
            if (gOpProviderList == null) gOpProviderList = new Hashtable();
            // Initialize the global abstract system and operation list
            if (gOpASList == null) gOpASList = new Hashtable();
            return true;
        }

        /// <summary>
        /// Terminate all Abstract System.
        /// </summary>
        /// <returns></returns>
        public static Boolean Terminate()
        {
            if (gOpProviderList.Count != 0)
            {
                ArrayList arrOp = new ArrayList(gOpProviderList.Keys);
                for (int i = 0; i < arrOp.Count; ++i)
                {
                    IAProvider iProvider = (IAProvider)gOpProviderList[arrOp[i]];
                    IAS iAS = (IAS)gOpASList[arrOp[i]];
                    iAS.ReleaseProvider(((IOperation)arrOp[i]).GetBindString(), ref iProvider);
                }
            }
            gOpProviderList = null;
            gOpASList = null;

            ArrayList arrType = new ArrayList(gTypeASList.Keys);
            for (int i = 0; i < arrType.Count; ++i)
            {
                try
                {
                    ((IAS)gTypeASList[arrType[i]]).End();
                }
                catch (System.Exception e)
                {
                    SMBL.Core.ErrorSystem.CatchError(e);
                }
            }
            return true;
        }

        /// <summary>
        /// Register the operation
        /// Require an IProvider and add both the operation and the provider to a hashtable
        /// @Author: Push
        /// </summary>
        /// <param name="TheOperation"></param>
        /// <returns></returns>
        public static Boolean Register(SMBL.Interface.Operation.IOperation TheOperation, Type ASType)
        {
            try
            {
                // Require for an IProvider
                // IDBProvider tmpProvider = ConnectionControl.GetConnection(TheOperation.GetBindString());
                IAS theAS = (IAS)gTypeASList[ASType.FullName];
                if (theAS == null) throw new Exception("Cannot find the AS of " + ASType.FullName);
                // Check availableness
                if (!theAS.IsAvailable) throw new Exception("The AS of " + ASType.FullName + " is not available!");
                // Get provider
                IAProvider tmpProvider = theAS.GetProvider(TheOperation.GetBindString());
                tmpProvider.Start();
                TheOperation.SetProcessor((IAProcessor)tmpProvider);

                // Register to the List
                gOpProviderList.Add(TheOperation, tmpProvider);
                gOpASList.Add(TheOperation, theAS.GetType().FullName);

                return true;
            }
            catch (Exception exp)
            {
                TheOperation.SetLastErrorId(ErrorSystem.CatchError(exp));
                return false;
            }
        }

        /// <summary>
        /// UnRegister the Operation with the Processor
        /// @Author: Push
        /// </summary>
        /// <param name="TheOperation"></param>
        /// <returns></returns>
        public static Boolean UnRegister(SMBL.Interface.Operation.IOperation TheOperation)
        {
            if (null == TheOperation || !gOpProviderList.ContainsKey(TheOperation))
            {
                // The operation hasn't registered yet.
                return false;
            }

            IAProvider tmpProvider = (IAProvider)gOpProviderList[TheOperation];
            IAS tmpAS = (IAS)gTypeASList[gOpASList[TheOperation]];
            // Remove the information
            TheOperation.ReleaseProcessor();
            gOpProviderList.Remove(TheOperation);
            gOpASList.Remove(TheOperation);

            // Release the provider.
            tmpAS.ReleaseProvider(TheOperation.GetBindString(), ref tmpProvider);
            return true;
        }

        /// <summary>
        /// Invoke the processDelegate method to do the process
        /// Any exception will be caught by the Control Center
        /// @Author: Push
        /// </summary>
        /// <param name="TheOperation"></param>
        /// <returns></returns>
        public static Boolean DoUnderControl(SMBL.Interface.Operation.IOperation TheOperation)
        {
            // Null reference check
            if (TheOperation == null) return false;

            // Invoke the operation's method to do everything
            try
            {
                TheOperation.processDelegate();
                return true;
            }
            catch (Exception exp)
            {
                TheOperation.SetLastErrorId(ErrorSystem.CatchError(exp));
                return false;
            }
        }
    }
}
